package com.neusoft.neuiotms.dcam.workflow.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.dto.ProcessInstanceDTO;
import com.neusoft.bizcore.activiti.model.WorkOrder;
import com.neusoft.bizcore.activiti.repository.WorkOrderRepository;
import com.neusoft.bizcore.activiti.service.ProcessInstanceService;
import com.neusoft.bizcore.activiti.service.WorkOrderService;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.converter.AssetConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetLifeCycleDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.model.AssetLifeCycle;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetLifeCycleRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetLifeCycleService;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;
import com.neusoft.neuiotms.dcam.workflow.converter.RukuFinanceAssetSLConverter;
import com.neusoft.neuiotms.dcam.workflow.converter.RukuFinanceConfirmSLConverter;
import com.neusoft.neuiotms.dcam.workflow.converter.RukuFinanceSLConverter;
import com.neusoft.neuiotms.dcam.workflow.dto.RukuFinanceAssetSLDTO;
import com.neusoft.neuiotms.dcam.workflow.dto.RukuFinanceSLDTO;
import com.neusoft.neuiotms.dcam.workflow.model.RukuFinanceAssetSL;
import com.neusoft.neuiotms.dcam.workflow.model.RukuFinanceConfirmAssetSL;
import com.neusoft.neuiotms.dcam.workflow.model.RukuFinanceConfirmSL;
import com.neusoft.neuiotms.dcam.workflow.model.RukuFinanceSL;
import com.neusoft.neuiotms.dcam.workflow.repository.RukuFinanceConfirmSLRepository;
import com.neusoft.neuiotms.dcam.workflow.repository.RukuFinanceSLRepository;
import com.neusoft.neuiotms.dcam.workflow.service.RukuFinanceSLService;

@Service
public class RukuFinanceSLServiceImpl implements RukuFinanceSLService {

    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private WorkOrderRepository workOrderRepository;
    @Autowired
    private ProcessInstanceService processInstanceService;
    @Autowired
    private RukuFinanceSLConverter rukuFinanceSLConverter;
    @Autowired
    private RukuFinanceSLRepository rukuFinanceSLRepository;
    @Autowired
    private RukuFinanceAssetSLConverter rukuFinanceAssetSLConverter;
    @Autowired
    private AssetConverter assetConverter;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private RukuFinanceConfirmSLRepository rukuFinanceConfirmSLRepository;
    @Autowired
    private RukuFinanceConfirmSLConverter rukuFinanceConfirmSLConverter;
    @Autowired
    private AssetLifeCycleService assetLifeCycleService;
    @Autowired
    private AssetLifeCycleRepository assetLifeCycleRepository;
    @Autowired
    private AssetService assetService;

    @Transactional
    @Override
    public RukuFinanceSLDTO create(final RukuFinanceSLDTO dto, final UserBean user) {

        final String taskId = dto.getTaskId();
        final ProcessInstanceDTO instance =
                this.workOrderService.submit(dto.getTitle(), DCAMConsts.PROCESSS_RUKU_FINANCE_SL_KEY,
                        dto.getWorkOrderNum(),
                        user);

        dto.setTaskId(instance.getTaskId());
        dto.setWorkOrderNum(instance.getWorkorderNum());

        // 查询当前workOrderNum和TaskId下是否存在记录
        final RukuFinanceSL oldModel = this.rukuFinanceSLRepository.findByWorkOrderNumAndTaskId(
                dto.getWorkOrderNum(), taskId);
        if (oldModel == null) {
            dto.setId(null);
        }

        RukuFinanceSL model = this.rukuFinanceSLConverter.toModel(dto);
        model = this.rukuFinanceSLRepository.save(model);

        // 完成当前节点s
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);
        // 生成资产信息
        // this.generateAssets(dto.getWorkOrderNum());

        // 判断合同是否已经全部到货
        // 更新合同状态为已到货

        return this.rukuFinanceSLConverter.toDTO(model);
    }

    @Override
    public RukuFinanceSLDTO detail(final String workOrderNum, final String taskId, final UserBean user) {
        RukuFinanceSL model = null;
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.rukuFinanceSLRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (lastTaskId == null) {
                        return new RukuFinanceSLDTO();
                    } else {
                        model = this.rukuFinanceSLRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                                lastTaskId);
                    }
                }
            } else if ("NULL".equals(taskId)) {
                model = this.rukuFinanceSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        final RukuFinanceSLDTO dto = this.rukuFinanceSLConverter.toDTO(model);

        return dto;
    }

    @Override
    public RukuFinanceSLDTO confirm(RukuFinanceSLDTO dto, UserBean user) {
        final RukuFinanceSL model =
                this.rukuFinanceSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(dto.getWorkOrderNum());

        final List<RukuFinanceAssetSL> removed = Lists.newArrayList();
        model.getAssetList().forEach(it -> {
            final RukuFinanceAssetSLDTO a =
                    dto.getAssetList().stream().filter(me -> me.getId().longValue() == it.getId().longValue())
                            .findFirst().orElse(null);
            if (null == a) {
                removed.add(it);
            }
        });

        removed.forEach(r -> {
            model.getAssetList().remove(r);
        });

        final RukuFinanceConfirmSL confirmSl = this.rukuFinanceSLConverter.copy(model);
        confirmSl.setTaskId(dto.getTaskId());
        final List<RukuFinanceConfirmAssetSL> confirmAssetSl = Lists.newArrayList();
        model.getAssetList().forEach(it -> {
            final RukuFinanceAssetSLDTO a =
                    dto.getAssetList().stream().filter(me -> me.getId().longValue() == it.getId().longValue())
                            .findFirst().orElse(null);
            if (null != a) {
                final RukuFinanceConfirmAssetSL asset = this.rukuFinanceAssetSLConverter.copy(a);
                asset.setRuku(confirmSl);
                confirmAssetSl.add(asset);
            }
        });

        confirmSl.setAssetList(confirmAssetSl);

        //this.rukuFinanceAssetSLRepository.deleteAll(removed);
        this.rukuFinanceConfirmSLRepository.save(confirmSl);
        //        this.rukuFinanceSLRepository.save(model);

        // 完成当前节点s
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);

        this.generateAssets(dto.getWorkOrderNum(), user);

        return this.rukuFinanceSLConverter.toDTO(model);
    }

    private List<AssetDTO> generateAssets(final String workOrderNum, UserBean user) {
        final List<AssetDTO> list = new ArrayList<>();
        final List<AssetLifeCycleDTO> lifeList = new ArrayList<>();
        final RukuFinanceConfirmSL main =
                this.rukuFinanceConfirmSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);

        final RukuFinanceSLDTO dto = this.rukuFinanceConfirmSLConverter.toDTO(main);

        final List<Asset> all = Lists.newArrayList();

        dto.getAssetList().forEach(it -> {
            final List<Asset> subAssets = this.assetConverter.toModels(it);
            all.addAll(subAssets);
        });

        this.assetRepository.saveAll(all);

        for (final Asset asset : all) {
            // 生命周期
            lifeList.add(AssetLifeCycleDTO.builder().userName(user.getName()).code(asset.getCode())
                    .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_TONGBUZONGHANG)
                    .content("财管资产同步").workNum(workOrderNum)
                    .build());
        }

        if (lifeList.size() > 0) {
            this.assetLifeCycleService.batchCreate(lifeList);
        }

        return list;
    }

    @Override
    public RukuFinanceSLDTO confirmDetail(String workOrderNum, String taskId, UserBean user) {
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                final RukuFinanceConfirmSL model =
                        this.rukuFinanceConfirmSLRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    //                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    //                    if (lastTaskId == null) {
                    //                        return new RukuFinanceSLDTO();
                    //                    } else {
                    //                        final RukuFinanceSL model1 =
                    //                                this.rukuFinanceSLRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                    //                                        lastTaskId);
                    //                        return this.rukuFinanceSLConverter.toDTO(model1);
                    //                    }
                    final RukuFinanceSL model1 =
                            this.rukuFinanceSLRepository
                                    .findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
                    return this.rukuFinanceSLConverter.toDTO(model1);
                } else {
                    return this.rukuFinanceConfirmSLConverter.toDTO(model);
                }
            } else if ("NULL".equals(taskId)) {
                final RukuFinanceConfirmSL model =
                        this.rukuFinanceConfirmSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
                return this.rukuFinanceConfirmSLConverter.toDTO(model);
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        return null;

    }

    @Override
    public List<RukuFinanceSLDTO> search(Searchable searchable) {
        final List<RukuFinanceSL> models = this.rukuFinanceSLRepository.search(searchable);
        return this.rukuFinanceSLConverter.toListDTO(models);
    }

    @Override
    public Page<RukuFinanceSLDTO> search(Pageable pageable, Searchable searchable) {

        final Searchable params = new Searchable();
        params.put("type", "RukuFinanceSL");
        params.put("status", "finish");
        final List<WorkOrder> finishedWorkorderList = this.workOrderRepository.search(params);
        final List<String> finishedWorkorderWorkNumList =
                finishedWorkorderList.stream().map(it -> it.getWorkOrderNum()).collect(Collectors.toList());

        searchable.put("workOrderNumIn", finishedWorkorderWorkNumList);
        final Page<RukuFinanceSL> models = this.rukuFinanceSLRepository.search(pageable, searchable);
        final Page<RukuFinanceSLDTO> dtos = this.rukuFinanceSLConverter.toPageDTO(models);
        return dtos;
    }

    @Override
    public RukuFinanceSLDTO detail(Long id) {
        final RukuFinanceSL model = this.rukuFinanceSLRepository.findById(id).orElse(null);
        if (null != model) {
            final RukuFinanceSLDTO dto = this.rukuFinanceSLConverter.toDTO(model);
            final List<AssetLifeCycle> assetList = this.assetLifeCycleRepository.findByWorkNum(model.getWorkOrderNum());
            if ((assetList != null) && !assetList.isEmpty()) {
                final List<String> codes = assetList.stream().map(l -> l.getCode()).collect(Collectors.toList());
                final Searchable searchable = new Searchable();
                searchable.put("codes", codes.toArray(new String[codes.size()]));
                dto.setAssetStandingBook(this.assetService.index(searchable));
            }
            return dto;
        }
        return null;
    }

}
